package main

import (
	//"fmt"

	"encoding/binary"
	"io"
	"io/ioutil"
	"os/exec"
	"sync"

	//"httpsproxy/ip2region"
	"log"
	"net"
	"os"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"time"

	"golang.org/x/net/dns/dnsmessage"
)

//域名信息
type HostInfo struct {
	isCN       bool               //是否中国域名
	Host       string             //域名
	ips        map[string]*IpInfo //ip数组
	time       int64              //处理时间
	dnsGETaddr []*DNSADDR         //请求查询ip的列表
	ms_jc      int64              //测速计次
	ms_ip      string             //抢到的加速
	isTcp      int64              //是否有tcp
	isHead     int64
}

//IP信息
type DNSADDR struct {
	msg  *dnsmessage.Message //FNS查询ID
	addr *net.UDPAddr
}

type IpInfo2 struct {
	CityId   int64
	Country  string
	Region   string
	Province string
	City     string
	ISP      string
}

//IP信息
type IpInfo struct {
	ms    int64  //响应时间
	ip    string //IP
	isCN  bool   //是否中国IP
	ms_jc int64  //测速计次
	isNOW int64  //是否正在使用

	isNOW1 int64 //是否正在使用
}

var errTime = int64(999999) //默认秒数
var logger = log.New(os.Stderr, "httpsproxy:", log.Llongfile|log.LstdFlags)
var fmt *log.Logger
var HostCache map[string]*HostInfo

//var IR *ip2region.Ip2Region
var serverDNS *net.UDPConn
var dns119 *net.UDPAddr
var dns1192 *net.UDPAddr
var dns119server *net.UDPConn

var xx8877 *net.UDPAddr
var mutexb = sync.Mutex{}

var isset = map[string]bool{} //是否已存在
//var allClient *http.Client
var serverDNSIP = []string{
	"223.6.6.6",       //保底
	"124.202.220.146", //华北->北京
	"202.96.69.38",    //东北->辽宁
	"124.133.43.90",   //华东->山东青岛
	"210.21.223.204",  //华南->广东
	"118.182.148.250", //西北->甘肃
	"218.75.136.129",  //华中->湖南
	"113.204.69.42",   //西南->重庆
	"221.179.40.22",   //广东汕头
	"211.162.62.1",    //广东广州
	"124.117.230.210", //新疆
	"202.14.67.4",     //香港
	"61.57.229.1",     //台湾
	"205.171.3.65",    //美国
	"203.2.193.67",    //澳大利亚
	"210.220.163.82",  //韩国
	"142.103.1.1",     //加拿大
	"211.121.135.130", //日本
	"91.214.72.33",    //意大利
	"5.159.215.254",   //英国
	"185.32.20.62",    //阿尔巴尼亚
	"195.214.240.136", //法国
	"80.64.32.2",      //西班牙
	"186.249.80.37",   //巴西
	"212.122.4.2",     //俄罗斯
	"82.96.64.2",      //德国
	"202.129.240.138", //印度
	"183.91.16.70",    //越南
	"202.136.162.11",  //新加坡
	"193.67.79.39",    //荷兰
	"208.67.222.222",  //保底
}

var packArr = map[string][]*net.UDPAddr{}

type dnsHttp struct {
	tcp   *net.Conn
	isRun bool
}

var allidnsHttp = []*dnsHttp{}

type ICMP struct {
	Type        uint8
	Code        uint8
	Checksum    uint16
	Identifier  uint16
	SequenceNum uint16
}

//DNS信息
type DnsInfo struct {
	ip     string   //IP
	conn   net.Conn //测速计次
	isSend bool     //是否忙碌中
}

var DNSserver map[string]*DnsInfo

var dnsip_all = "119.29.29.29"

var all_port = int(8287)

func main() {
	conn2, _ := net.ListenUDP("udp", &net.UDPAddr{})
	dns119server = conn2
	dnsss2, _ := net.ResolveUDPAddr("udp4", "192.168.1.201:8877")
	xx8877 = dnsss2

	/*
		allClient = &http.Client{
			Timeout: 2000 * time.Millisecond,
			CheckRedirect: func(req *http.Request, via []*http.Request) error {
				return errors.New("something bad happened") // 禁止重定向
			},
			Transport: &http.Transport{
				MaxIdleConnsPerHost: 60,
				DisableKeepAlives:   false,
				DisableCompression:  false,
			},
		}
	*/
	runtime.GOMAXPROCS(1) //要啥自行车 单线程够了
	Exedir, r2ee := os.Executable()

	fmt = logger
	logger.Println("启动..请稍候 -D 临时调试显示日志(半小时自动关闭)  -P53 指定使用53端口(默认8287)", Exedir)
	for _, v := range os.Args {
		if v == "-D" {
			Exedir = ""
		}
		if v == "-P53" {
			all_port = int(53)
		}
		//i = i
	}
	if r2ee == nil && Exedir != "" {
		var cmd *exec.Cmd
		for {
			logger.Println("-D 子进程启动中...", Exedir)
			if all_port == 53 {
				cmd = exec.Command(Exedir, "-D", "-P53")
			} else {
				cmd = exec.Command(Exedir, "-D")
			}

			cmd.Start()
			cmd.Wait()
		}
	}

	for {
		connx, err3 := net.DialTimeout("tcp", "223.6.6.6:80", 10*time.Second) // 3s timeout
		if err3 != nil {
			fmt.Println("223.6.6.6:80连接失败", err3)
			time.Sleep(1 * time.Second)
			continue
		}
		connx.Close()
		break
	}

	/*for {
		time.Sleep(1 * time.Second)
	}*/

	/*
		var icmp ICMP

		icmp.Type = 8
		icmp.Code = 0
		icmp.Checksum = 0
		icmp.Identifier = 0
		icmp.SequenceNum = 0

		var buffer bytes.Buffer
		binary.Write(&buffer, binary.BigEndian, icmp)
		icmp.Checksum = CheckSum(buffer.Bytes())
		buffer.Reset()
		binary.Write(&buffer, binary.BigEndian, icmp)
		buf := buffer.Bytes()
		fmt.Print(buf)
	*/

	argx := "route |grep default |awk '{print $2}'"
	cmd := exec.Command("/bin/sh", "-c", argx)
	outx, erraa := cmd.Output()
	fmt.Println("自动识别dns结果", string(outx), erraa)
	if erraa == nil {
		lsip := string(outx)
		//检查ip合法
		if len(lsip) <= 15 && len(lsip) >= 7 && len(strings.Split(lsip, ".")) == 4 {
			serverDNSIP[0] = strings.Replace(strings.Replace(lsip, "\n", "", -1), "\r", "", -1)
			fmt.Println("自动识别dns结果", dnsip_all)
		}
	}

	dnsip_all = serverDNSIP[0]
	//dnsip_all = "119.29.29.29"
	fmt.Println("使用dns", dnsip_all)

	DNSserver = make(map[string]*DnsInfo)
	for i := 0; i < len(serverDNSIP); i++ {
		go addDns(serverDNSIP[i])
		//conn.Close()
	}

	HostCache = make(map[string]*HostInfo)
	/*
		region, err := ip2region.New("ip2region.db")
		if err != nil {
			fmt.Println(err, "自动加载/home/GoAutoDns/ip2region.db")
			region, err = ip2region.New("/home/GoAutoDns/ip2region.db")
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
		}
		IR = region
	*/
	conn, err2 := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("0.0.0.0"), Port: all_port})
	if err2 != nil {
		fmt.Println("端口监听失败", all_port, err2)
		os.Exit(1)
	}
	serverDNS = conn

	logger.Println("启动完成")

	dnsss, _ := net.ResolveUDPAddr("udp4", dnsip_all+":53")
	dns119x, _ := net.ResolveUDPAddr("udp4", "119.29.29.29:53")
	//dnsss, _ := net.ResolveUDPAddr("udp4", "211.162.61.236:53") //长城专用
	dns119 = dnsss
	dns1192 = dns119x

	go dns119run()
	go httpProxy(all_port)
	go exitxx()
	//defer serverDNS.Close()
	for {
		buf := make([]byte, 1024)
		n, addr, errx := serverDNS.ReadFromUDP(buf)
		if errx != nil || n < 3 {
			continue
		}
		buf = buf[:n]

		//fmt.Println(addr)
		//dns119server.WriteToUDP(buf, addr)
		go dnsmsg(buf, addr)
		dns119server.WriteToUDP(buf, dns119)
		dns119server.WriteToUDP(buf, dns1192)

	}

}

func exitxx() {
	path := "/tmp/LingMaxDns" + strconv.Itoa(int(timems()/1000/86400)) + ".cache"
	bb, errx := ioutil.ReadFile(path)
	ss := ""
	if errx == nil {
		ss = string(bb)
	}

	arr := strings.Split(ss, "\n")
	for i := 0; i < len(arr); i++ {
		if arr[i] == "" {
			continue
		}
		arrx := strings.Split(arr[i], "@")
		if len(arrx) != 2 {
			continue
		}

		HostCache[arrx[1]] = &HostInfo{
			isCN:       false,                    //是否中国域名
			Host:       arrx[1],                  //域名
			ips:        make(map[string]*IpInfo), //ip数组
			time:       0,                        //处理时间
			dnsGETaddr: []*DNSADDR{},             //请求查询ip的列表
			ms_jc:      0,
			ms_ip:      arrx[0],
			isTcp:      0,
			isHead:     0,
		}
		HostCache[arrx[1]].ips[arrx[0]] = &IpInfo{
			ms:     100,     //响应时间
			ip:     arrx[0], //IP
			isCN:   false,   //是否中国IP
			ms_jc:  0,       //测速计次
			isNOW:  0,
			isNOW1: 0,
		}
	}

	for i := 0; i < 1800; i++ {
		time.Sleep(1 * 1000 * time.Millisecond)
		if os.Getppid() == 1 {
			os.Exit(2)
		}
		// strconv.Itoa(os.Getppid())
	}

	mutexb.Lock()
	str := ""
	for host := range HostCache {
		if len(HostCache[host].ms_ip) > 0 {
			str += HostCache[host].ms_ip + "@" + host + "\n"
		}
	}

	ioutil.WriteFile(path, []byte(str), 0777) //写入文件(字节数组)

	os.Exit(1)
}

func addDns(ip string) {
	for {
		_, ok := DNSserver[ip]
		if !ok {
			time.Sleep(1 * time.Second)
			continue
		}

		buf := make([]byte, 1024)

		len1, err := DNSserver[ip].conn.Read(buf)
		if err != nil || len1 < 3 {
			time.Sleep(1 * time.Second)
			continue
		}
		buf = buf[:len1]
		buf = buf[2:] // tcp包转UDP包
		// alldata(buf, true)
	}
}
func dns119run() {
	for {
		buf2 := make([]byte, 1024)
		n, _, errx := dns119server.ReadFromUDP(buf2)
		if errx != nil || n < 3 {
			continue
		}
		buf2 = buf2[:n]
		alldata(buf2, false)
	}
}
func alldata(buf []byte, bz bool) string {
	var msg dnsmessage.Message
	if err := msg.Unpack(buf); err != nil {
		return ""
	}
	if len(msg.Questions) < 1 {
		return ""
	}
	question := msg.Questions[0]
	host := question.Name.String()
	//host = host[:len(host)-1]
	ipv4 := ""

	ipv4x := ""
	issetx := false
	nrnr := ""

	if bz {
		nrnr = nrnr + " bz "
	}
	mutexb.Lock()
	for i := 0; i < len(msg.Answers); i++ {
		msg.Answers[i].Header.TTL = 5
		if dnsmessage.TypeA == msg.Answers[i].Header.Type && len(ipv4) > 0 {
			b := msg.Answers[i].Body.(*dnsmessage.AResource).A
			ipv4 := strconv.Itoa(int(b[0])) + "." + strconv.Itoa(int(b[1])) + "." + strconv.Itoa(int(b[2])) + "." + strconv.Itoa(int(b[3]))
			_, ok4 := HostCache[host]
			if ok4 {
				_, ok3 := HostCache[host].ips[ipv4]
				if !ok3 {
					issetx = true
					nrnr = nrnr + " isset "
				}
				go checkAdress(host, ipv4, !bz)
			}
		}
	}
	mutexb.Unlock()
	if issetx {
		time.Sleep(60 * time.Millisecond)
	}
	mutexb.Lock()
	ttts := errTime
	for i := 0; i < len(msg.Answers); i++ {
		if dnsmessage.TypeA == msg.Answers[i].Header.Type {
			b := msg.Answers[i].Body.(*dnsmessage.AResource).A

			ipv4 := strconv.Itoa(int(b[0])) + "." + strconv.Itoa(int(b[1])) + "." + strconv.Itoa(int(b[2])) + "." + strconv.Itoa(int(b[3]))
			_, ok4 := HostCache[host]
			if ok4 {
				_, ok3 := HostCache[host].ips[ipv4]
				if ok3 {

					nrnr = nrnr + "   " + ipv4 + "ms" + strconv.Itoa(int(HostCache[host].ips[ipv4].ms))
				}
				if !bz && ok3 && HostCache[host].ips[ipv4].ms > 60 && len(HostCache[host].ms_ip) > 0 && len(ipv4x) < 1 {
					ipv4x = HostCache[host].ms_ip
					//msg.Answers[i].Body.(*dnsmessage.AResource).A = ipToByte(HostCache[host].ms_ip)
				} else {
					if bz {
						break
					}
					if ok3 && HostCache[host].ips[ipv4].ms > 0 && HostCache[host].ips[ipv4].ms < 60 && HostCache[host].ips[ipv4].ms < ttts && len(HostCache[host].ms_ip) > 0 {
						ipv4x = ipv4
						ttts = HostCache[host].ips[ipv4].ms
					}
				}
			}
		}
	}

	for i := 0; i < len(msg.Answers); i++ {
		msg.Answers[i].Header.TTL = 5
		if dnsmessage.TypeA == msg.Answers[i].Header.Type && len(ipv4x) > 0 {
			msg.Answers[i].Body.(*dnsmessage.AResource).A = ipToByte(ipv4x)
		}
	}
	mutexb.Unlock()
	mkey := host + "_" + strconv.Itoa(int(msg.Header.ID))
	if !bz {
		//fmt.Println(mkey)
	}
	mutexb.Lock()
	_, ok1 := packArr[mkey]
	mutexb.Unlock()
	if !ok1 || bz {
		return ""
	}

	xx("最终得到" + host + " => ip" + ipv4x + "预备IP" /*+ HostCache[host].ms_ip */ + nrnr)
	mutexb.Lock()
	buf3, _ := msg.Pack()
	for i := 0; i < len(packArr[mkey]); i++ {
		addr := packArr[mkey][i]
		serverDNS.WriteToUDP(buf3, addr)
	}
	packArr[mkey] = []*net.UDPAddr{}
	mutexb.Unlock()
	return ipv4
}

func sendDns(host string, buf []byte) {
	isall := false
	mutexb.Lock()
	if HostCache[host].time < timems()-1000*60*30 || timems()-1000*30 > HostCache[host].time && len(HostCache[host].ips) == 0 {
		for i := 0; i < len(serverDNSIP); i++ {
			// go host2ip(host, serverDNSIP[i], buf)
			go host2ipHttp(host, serverDNSIP[i])
		}
		go host2ipHttp(host, "113.96.18.253")  //广州电信 特地加上 TIM故障
		go host2ipHttp(host, "113.70.38.1")    //佛山电信 特地加上 TIM故障
		go host2ipHttp(host, "220.231.153.40") //深圳电信 特地加上 TIM故障
		go host2ipHttp(host, "221.4.219.163")  //珠海电信 特地加上 TIM故障

		isall = true
	}
	mutexb.Unlock()
	isret := timems()-1000*3 < HostCache[host].time

	if isret && len(HostCache[host].ms_ip) > 0 {
		goDNS(host, HostCache[host].ms_ip, HostCache[host].ms_jc, "缓存")
		return
	}

	d1 := []*IpInfo{}

	mutexb.Lock() //mutex.Unlock()
	for vip := range HostCache[host].ips {
		d1 = append(d1, HostCache[host].ips[vip])
	}
	mutexb.Unlock()
	sort.Slice(d1, func(i, j int) bool {
		return d1[i].ms < d1[j].ms
		//return rand.Intn(1) == 1
	})

	HostCache[host].time = timems()
	mmss := int64(40)
	if len(HostCache[host].ms_ip) > 0 {
		go checkAdress(host, HostCache[host].ms_ip, false)
		time.Sleep(20 * time.Millisecond)
	}
	for i := 0; i < len(d1); i++ {
		if HostCache[host].ms_ip == d1[i].ip {
			continue
		}
		if i > 3 && !isall {
			break
		}
		if i == 0 && d1[i].ms == errTime {
			//goDNS(host, d1[i].ip, HostCache[host].ms_jc, "没有加速成功先顶着")
		}
		go checkAdress(host, d1[i].ip, false)
		if i > 1 && isall {
			time.Sleep(time.Duration(mmss) * time.Millisecond)
			mmss = int64(float64(mmss) * float64(0.6))
		}
		if i > 3 && !isall && len(HostCache[host].dnsGETaddr) < 1 {
			break
		}
	}
}
func host2ip(host string, ip string, buf []byte) {
	_, ok := DNSserver[ip]
	if !ok {
		conn, err2 := net.DialTimeout("tcp", ip+":53", 2*time.Second)
		if err2 != nil {
			return
		}
		DNSserver[ip] = &DnsInfo{
			ip:     ip,
			conn:   conn,
			isSend: false,
		}
	}

	buf2 := make([]byte, 2)
	binary.BigEndian.PutUint16(buf2, uint16(len(buf)))

	buf = append(buf2, buf...)
	//fmt.Println(buf, uint16(len(buf)))
	//buf := make([]byte, 1024)
	_, err := DNSserver[ip].conn.Write(buf)
	if err != nil {
		if DNSserver[ip].isSend {
			return
		}
		DNSserver[ip].isSend = true
		DNSserver[ip].conn.Close()
		conn, err2 := net.DialTimeout("tcp", ip+":53", 2*time.Second)
		DNSserver[ip].isSend = false
		if err2 != nil {
			return
		}
		DNSserver[ip].conn = conn
		DNSserver[ip].conn.Write(buf)
	}
}

func host2ipHttp(host string, ip string) {
	if len(host) < 2 {
		return
	}
	host1 := string(host[:len(host)-1])

	ix := -1
	for ixc := 0; ixc < len(allidnsHttp); ixc++ {
		if !allidnsHttp[ixc].isRun {
			ix = ixc
			break
		}
	}
	if ix == -1 {
		conn1, err := net.DialTimeout("tcp", "223.6.6.6:80", 3*time.Second) // 3s timeout
		if err != nil {
			return
		}
		mutexb.Lock()
		allidnsHttp = append(allidnsHttp, &dnsHttp{tcp: &conn1, isRun: false})
		mutexb.Unlock()
		ix = len(allidnsHttp) - 1
	}

	allidnsHttp[ix].isRun = true
	conn := *allidnsHttp[ix].tcp
	defer func() { allidnsHttp[ix].isRun = false }()

	strx := "GET /resolve?name=" + host1 + "&type=A&short=1&edns_client_subnet=" + ip + " HTTP/1.1\r\nHost: 223.6.6.6\r\nConnection:keep-alive\r\nUser-Agent: Mozilla/5.0\r\nAccept: */*\r\nContent-Length: 0\r\n\r\n"
	_, err := conn.Write([]byte(strx))
	if err != nil {
		conn2, err := net.DialTimeout("tcp", "223.6.6.6:80", 3*time.Second) // 3s timeout
		if err != nil {
			return
		}
		allidnsHttp[ix].tcp = &conn2
		conn = *allidnsHttp[ix].tcp
		conn.Write([]byte(strx))
	}
	conn.SetReadDeadline((time.Now().Add(time.Millisecond * 1500)))
	body := make([]byte, 2048)
	len1, err := conn.Read(body)
	if err != nil || len1 < 3 {
		return
	}
	body = body[:len1]
	/*
		resp, err := allClient.Get("http://223.6.6.6/resolve?name=" + host + "&type=A&short=1&edns_client_subnet=" + ip)

		if err != nil {
			return
		}
		defer resp.Body.Close()
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil || len(body) < 3 {
			return
		}
		ss := string(body)
	*/
	if err != nil || len(body) < 3 {
		return
	}
	ss := string(body)

	ret := strings.Split(ss, "\r\n\r\n")
	if len(ret) < 2 {
		return
	}

	ss = ret[1]
	if len(ss) < 3 {
		return
	}

	ss = ss[1 : len(ss)-1]
	ss = strings.Replace(ss, "\"", "", -1)
	ips := strings.Split(ss, ",")
	for i := 0; i < len(ips); i++ {
		go checkAdress(host, ips[i], false)
	}

}

func CheckSum(data []byte) uint16 {
	var (
		sum    uint32
		length int = len(data)
		index  int
	)
	for length > 1 {
		sum += uint32(data[index])<<8 + uint32(data[index+1])
		index += 2
		length -= 2
	}
	if length > 0 {
		sum += uint32(data[index])
	}
	sum += (sum >> 16)

	return uint16(^sum)
}

func dnsmsg(buf []byte, addr *net.UDPAddr) {
	if dnsmsg2(buf, addr) {
		return
	}
	return
	conn, err2 := net.ListenUDP("udp", &net.UDPAddr{})
	if err2 != nil {
		fmt.Println(err2)
		return
	}
	defer conn.Close()
	conn.WriteToUDP(buf, dns119)
	conn.WriteToUDP(buf, dns1192)
	conn.SetReadDeadline((time.Now().Add(time.Second * 1)))
	buf2 := make([]byte, 1024)
	n, _, errx := conn.ReadFromUDP(buf2)
	if errx != nil {
		return
	}
	buf2 = buf2[:n]
	serverDNS.WriteToUDP(buf2, addr)
	//fmt.Println("没有加速成功 用默认DNS")
}

func dnsmsg2(buf []byte, addr *net.UDPAddr) bool {
	//return false
	var msg dnsmessage.Message
	if err := msg.Unpack(buf); err != nil {
		//fmt.Println("解包失败", err)
		return false
	}
	if len(msg.Questions) < 1 {
		//fmt.Println("查询数量异常", msg)
		return false
	}
	question := msg.Questions[0]
	host := question.Name.String()

	//host = host[:len(host)-1]
	mkey := host + "_" + strconv.Itoa(int(msg.Header.ID))
	mutexb.Lock()
	_, ok1 := packArr[mkey]
	if !ok1 {
		packArr[mkey] = []*net.UDPAddr{}
	}
	packArr[mkey] = append(packArr[mkey], addr)
	mutexb.Unlock()
	go delset(mkey)
	if dnsmessage.TypePTR == question.Type {
		return true
		ip := strings.Replace(host, ".in-addr.arpa.", "", 1)
		msg.Response = true
		name, _ := dnsmessage.NewName(ip)
		rt := dnsmessage.Resource{
			Header: dnsmessage.ResourceHeader{
				Name:  question.Name,
				Class: dnsmessage.ClassINET,
				TTL:   5,
			},
			Body: &dnsmessage.PTRResource{
				PTR: name,
			},
		}
		msg.Answers = []dnsmessage.Resource{rt}
		buf3, _ := msg.Pack()
		serverDNS.WriteToUDP(buf3, addr)
		return true
	}

	/*
			if dnsmessage.TypeA != question.Type {
				fmt.Println("不是查询IP", host)
				return false
			}

		if host == "m.baidu.com." {
			fmt.Println("放行", host)
			return false
		}
	*/
	//fmt.Println(question, 111, msg)
	mutexb.Lock()
	_, ok := HostCache[host]

	//fmt.Println(HostInfo1, ok)
	if !ok {
		HostCache[host] = &HostInfo{
			isCN:       false,                    //是否中国域名
			Host:       host,                     //域名
			ips:        make(map[string]*IpInfo), //ip数组
			time:       0,                        //处理时间
			dnsGETaddr: []*DNSADDR{},             //请求查询ip的列表
			ms_jc:      0,
			ms_ip:      "",
			isTcp:      0,
			isHead:     0,
		}
	}
	HostCache[host].dnsGETaddr = append(HostCache[host].dnsGETaddr, &DNSADDR{
		msg:  &msg,
		addr: addr,
	})
	mutexb.Unlock()
	if len(HostCache[host].dnsGETaddr) > 1 {
		return true
	}
	xx("查询域名" + host)
	ms_jc := HostCache[host].ms_jc
	sendDns(host, buf)
	return false
	time.Sleep(1000 * time.Millisecond)
	if ms_jc != HostCache[host].ms_jc {
		return true
	}
	//fmt.Println("查询超时", host)
	return false

}
func delset(mkey string) {
	time.Sleep(4000 * time.Millisecond)
	mutexb.Lock()
	delete(packArr, mkey)
	mutexb.Unlock()
}

func ipToByte(ip string) [4]byte {
	a := [4]byte{0, 0, 0, 0}
	ips := strings.Split(ip, ".")
	if len(ips) != 4 {
		return a
	}
	for i := 0; i < len(ips); i++ {
		xi, _ := strconv.Atoi(ips[i])
		a[i] = byte(xi)
	}
	return a
}

func NewAResource(host string, ip string) dnsmessage.Resource {

	ips := strings.Split(ip, ".")
	a := [4]byte{0, 0, 0, 0}

	for i := 0; i < len(ips); i++ {
		xi, _ := strconv.Atoi(ips[i])
		a[i] = byte(xi)
	}
	query, _ := dnsmessage.NewName(host)
	return dnsmessage.Resource{
		Header: dnsmessage.ResourceHeader{
			Name:  query,
			Class: dnsmessage.ClassINET,
			TTL:   5,
		},
		Body: &dnsmessage.AResource{
			A: a,
		},
	}
}

//启动检查
func checkAdress(host string, ip string, isdns bool) bool {
	if ip == "20.205.243.166" || ip == "175.178.31.156" {
		return false
	}
	if ip == "157.255.77.80" {
		return false
	}
	_, errxy := net.ResolveIPAddr("ip", ip) // 解析域名得到 IP 地址结构
	if errxy != nil {
		return false
	}
	addr := getAddr(ip)
	if addr.Country == "内网IP" {
		return false
	}
	mutexb.Lock()
	_, ok1 := HostCache[host].ips[ip]
	mutexb.Unlock()
	//fmt.Println(IpInfo1, ok)
	if !ok1 {

		//检查是否有同ip段的ip 如果有则过滤掉
		ips := strings.Split(ip, ".")
		if len(ips) != 4 {
			return false
		}
		mutexb.Lock()
		_, ok2 := isset[host+"_"+ips[0]+"."+ips[1]+"."+ips[2]+"."]
		mutexb.Unlock()
		if ok2 && !isdns {
			return false
		}
		mutexb.Lock()
		isset[host+"_"+ips[0]+"."+ips[1]+"."+ips[2]+"."] = true

		//addr, _ := IR.BtreeSearch(ip)
		//addr, _ := IR.MemorySearch(ip)
		//isCN := addr.Country == "中国" || addr.City == "内网IP"
		HostCache[host].ips[ip] = &IpInfo{
			ms:     99999, //响应时间
			ip:     ip,    //IP
			isCN:   false, //是否中国IP
			ms_jc:  0,     //测速计次
			isNOW:  0,
			isNOW1: 0,
		}
		mutexb.Unlock()
		/*if isCN {
			HostCache[host].isCN = isCN
		}*/
		//fmt.Println(host, ip)
	} else {
		if len(HostCache[host].dnsGETaddr) < 1 {
			return false
		}
		mutexb.Lock()
		if HostCache[host].ips[ip].isNOW > 0 || HostCache[host].ips[ip].isNOW1 > 0 {
			mutexb.Unlock()
			return false
		}
		mutexb.Unlock()
	}
	HostCache[host].isTcp = HostCache[host].ms_jc
	go checkTcp(host, ip, HostCache[host].ms_jc)
	go checkPing(host, ip, HostCache[host].ms_jc)
	time.Sleep(10 * time.Millisecond)
	go checkTcp(host, ip, HostCache[host].ms_jc)
	go checkPing(host, ip, HostCache[host].ms_jc)
	//ms_jc := HostCache[host].ms_jc
	mutexb.Lock()
	HostCache[host].ips[ip].isNOW1++
	mutexb.Unlock()
	time.Sleep(2000 * time.Millisecond)
	mutexb.Lock()
	HostCache[host].ips[ip].isNOW1--
	mutexb.Unlock()
	return true
}

//tcp测速
func checkTcp(host string, ip string, ms_jc int64) bool {
	//time.Sleep(time.Duration(rand.Intn(10)) * time.Millisecond)
	//fmt.Println("开始" + host + " =>  " + ip)
	ts := timems()
	mutexb.Lock()
	if ms_jc < HostCache[host].ips[ip].ms_jc || len(HostCache[host].dnsGETaddr) < 1 {
		mutexb.Unlock()
		return false
	}
	HostCache[host].ips[ip].isNOW++
	mutexb.Unlock()
	conn, err := net.DialTimeout("tcp", ip+":80", 2*time.Second) // 3s timeout
	mutexb.Lock()
	HostCache[host].ips[ip].isNOW--

	//fmt.Println("结束" + host + " =>  " + ip)
	if err != nil {
		if ms_jc == HostCache[host].ips[ip].ms_jc {
			HostCache[host].ips[ip].ms = errTime
		}
		mutexb.Unlock()
		return false
	}
	defer conn.Close()
	if ms_jc < HostCache[host].ips[ip].ms_jc {
		mutexb.Unlock()
		return false
	}

	HostCache[host].ips[ip].ms = timems() - ts
	mutexb.Unlock()
	conn.Write([]byte("HEAD / HTTP/1.1\r\nHost: " + host + "\r\nUser-Agent: Mozilla/5.0\r\nAccept: */*\r\nContent-Length: 0\r\n\r\n"))
	conn.SetReadDeadline((time.Now().Add(time.Millisecond * 2000)))
	buf := make([]byte, 1024)
	len1, err := conn.Read(buf)
	mutexb.Lock()
	if (err != nil || len1 < 4 || string(buf[:4]) != "HTTP") && HostCache[host].isHead > 0 && len(HostCache[host].ips) > 1 {
		mutexb.Unlock()
		return false
	}
	HostCache[host].isHead = HostCache[host].ms_jc + 1

	HostCache[host].ips[ip].ms = timems() - ts
	mutexb.Unlock()
	goDNS(host, ip, ms_jc, "TCP加速成功")

	return true
}

//ping测速
func checkPing(host string, ip string, ms_jc int64) bool {
	// time.Sleep(10 * time.Millisecond)
	//if HostCache[host].isTcp+1 >= HostCache[host].ms_jc && HostCache[host].isTcp != 0 {
	//	time.Sleep(200 * time.Millisecond)
	//} else {
	//	time.Sleep(time.Duration(rand.Intn(10)) * time.Millisecond)
	//}
	mutexb.Lock()
	if ms_jc < HostCache[host].ips[ip].ms_jc || len(HostCache[host].dnsGETaddr) < 1 {
		mutexb.Unlock()
		return false
	}
	mutexb.Unlock()
	ts := timems()
	laddr := net.IPAddr{IP: net.ParseIP("0.0.0.0")} // 得到本机的IP地址结构
	raddr, errxy := net.ResolveIPAddr("ip", ip)     // 解析域名得到 IP 地址结构
	if errxy != nil {
		return false
	}
	conn, err := net.DialIP("ip4:icmp", &laddr, raddr)

	if err != nil {
		return false
	}
	defer conn.Close()
	recv := make([]byte, 1024)
	buf := []byte{8, 0, 247, 255, 0, 0, 0, 0}

	if _, err := conn.Write(buf); err != nil {
		//fmt.Println(err.Error())
		return false
	}
	conn.SetReadDeadline((time.Now().Add(time.Second * 2)))
	mutexb.Lock()
	HostCache[host].ips[ip].isNOW++
	mutexb.Unlock()
	_, err3 := conn.Read(recv)
	mutexb.Lock()
	HostCache[host].ips[ip].isNOW--

	if err3 != nil {
		if ms_jc == HostCache[host].ips[ip].ms_jc {
			HostCache[host].ips[ip].ms = errTime
		}
		mutexb.Unlock()
		return false
	}
	mutexb.Unlock()

	time.Sleep(5 * time.Millisecond)
	recv = make([]byte, 1024)
	if _, err := conn.Write(buf); err != nil {
		//fmt.Println(err.Error())
		return false
	}
	conn.SetReadDeadline((time.Now().Add(time.Second * 2)))
	mutexb.Lock()
	HostCache[host].ips[ip].isNOW++
	mutexb.Unlock()
	_, err8 := conn.Read(recv)
	mutexb.Lock()
	HostCache[host].ips[ip].isNOW--

	if err8 != nil {
		if ms_jc == HostCache[host].ips[ip].ms_jc {
			HostCache[host].ips[ip].ms = errTime
		}
		mutexb.Unlock()
		return false
	}
	mutexb.Unlock()

	time.Sleep(5 * time.Millisecond)
	recv = make([]byte, 1024)

	if _, err := conn.Write(buf); err != nil {
		//fmt.Println(err.Error())
		return false
	}
	conn.SetReadDeadline((time.Now().Add(time.Second * 2)))
	mutexb.Lock()
	HostCache[host].ips[ip].isNOW++
	mutexb.Unlock()
	_, err4 := conn.Read(recv)
	mutexb.Lock()
	HostCache[host].ips[ip].isNOW--

	if err4 != nil {
		if ms_jc == HostCache[host].ips[ip].ms_jc {
			HostCache[host].ips[ip].ms = errTime
		}
		mutexb.Unlock()
		return false
	}

	/*if len1 != len(buf) {
		fmt.Println("长度异常", len1)
		return false
	}*/

	if ms_jc < HostCache[host].ips[ip].ms_jc {
		mutexb.Unlock()
		return false
	}

	HostCache[host].ips[ip].ms = timems() - ts
	mutexb.Unlock()
	goDNS(host, ip, ms_jc, "ping加速成功")

	return true
}

func goDNS(host string, ip string, ms_jc int64, from string) {
	mutexb.Lock()
	HostCache[host].ips[ip].ms_jc = HostCache[host].ms_jc
	if ms_jc != HostCache[host].ms_jc && !(from == "TCP加速成功" && ms_jc > HostCache[host].isTcp) {
		mutexb.Unlock()
		return
	}
	/*
		hostby, _ := dnsmessage.NewName(host)
		ips := strings.Split(ip, ".")
		a := [4]byte{0, 0, 0, 0}

		for i := 0; i < len(ips); i++ {
			xi, _ := strconv.Atoi(ips[i])
			a[i] = byte(xi)
		}

			msg := dnsmessage.Message{
				Header: dnsmessage.Header{Response: true, Authoritative: true},
				Questions: []dnsmessage.Question{
					{
						Name:  hostby,
						Type:  dnsmessage.TypeA,
						Class: dnsmessage.ClassINET,
					},
				},
				Answers: []dnsmessage.Resource{
					{
						Header: dnsmessage.ResourceHeader{
							Name:  hostby,
							Type:  dnsmessage.TypeA,
							Class: dnsmessage.ClassINET,
							TTL:   5,
						},
						Body: &dnsmessage.AResource{A: a},
					},
				},
			}
	*/
	HostCache[host].ms_jc++
	/*
		for i := 0; i < len(HostCache[host].dnsGETaddr); i++ {
			msg := HostCache[host].dnsGETaddr[i].msg
			msg.Response = true
			msg.Answers = []dnsmessage.Resource{NewAResource(host, ip)}
			buf, _ := msg.Pack()
			serverDNS.WriteToUDP(buf, HostCache[host].dnsGETaddr[i].addr)
		}
	*/

	HostCache[host].dnsGETaddr = []*DNSADDR{}
	HostCache[host].ips[ip].ms_jc = HostCache[host].ms_jc
	if len(ip) > 0 && string(ip[len(ip)-1:]) != "." {
		HostCache[host].ms_ip = ip
	}
	if from == "TCP加速成功" {
		HostCache[host].isTcp = HostCache[host].ms_jc
	}

	xx("解析成功" + from + host + " => ip" + ip + " 延迟" + strconv.Itoa(int(HostCache[host].ips[ip].ms)))
	//fmt.Println(from, "查询成功", HostCache[host].ips[ip].ms, "域名", host, "=>", ip)
	mutexb.Unlock()
}

//获取毫秒
func timems() int64 {
	return time.Now().UnixNano() / 1e6
}

func getAddr(ip string) IpInfo2 {
	s3 := string(ip[0:3])

	Country1 := ""
	City1 := ""
	if string(ip[0:1]) == "0" || s3 == "127" || s3 == "10." {
		City1 = "内网IP"
		Country1 = "内网IP"
	} else {
		s7 := string(ip[0:7])
		if s7 == "192.168" || s7 == "172.16." || s7 == "172.17." || s7 == "172.18." || s7 == "172.19." || s7 == "172.20." || s7 == "172.21." || s7 == "172.22." || s7 == "172.23." || s7 == "172.24." || s7 == "172.25." || s7 == "172.26." || s7 == "172.27." || s7 == "172.28." || s7 == "172.29." || s7 == "172.30." || s7 == "172.31." {
			City1 = "内网IP"
			Country1 = "内网IP"
		}
	}

	return IpInfo2{Country: Country1, City: City1}
}

//输出信息
func xx(str string) {
	logger.Println("xx 调试消息" + str)
	dns119server.WriteToUDP([]byte(str), xx8877)
}

//https代理
func httpProxy(port int) {
	server, err := net.Listen("tcp", "0.0.0.0:"+strconv.Itoa(all_port))
	if err != nil {
		logger.Println("https代理其他失败")
		return
	}
	defer server.Close()
	for {
		Conn, err := server.Accept()
		if err != nil {
			return
		}
		go tcp_handle(&Conn)
	}

}

func tcp_handle(Conn *net.Conn) {

	buf := make([]byte, 4096)
	len1, err := (*Conn).Read(buf)
	if err != nil || len1 < 10 {
		return
	}
	str := string(buf[:len1])

	wz_head := strings.Index(str, "\r\nHost: ")
	if wz_head < 0 {
		return
	}

	wz_head = wz_head + 8
	wz_end := strings.Index(str[wz_head:], "\r\n")
	if wz_end < 0 {
		return
	}
	wz_end = wz_end + wz_head
	hostPort := str[wz_head:wz_end]
	listArr := strings.Split(hostPort, ":")
	host := ""
	port := ""
	if len(listArr) == 2 {
		host = listArr[0]
		port = listArr[1]
	} else if len(listArr) == 1 {
		host = listArr[0]
		port = "0"
	} else {
		return
	}

	head_len := strings.Index(str, "\r\n\r\n")
	if wz_end > head_len || head_len == -1 {
		return
	}
	ver := "HTTP/1.0"
	head_len = head_len + 4
	ls := strings.Index(str, " HTTP/")
	if ls > head_len || ls == -1 {
		return
	}

	/*
		ver = str[ls+1 : strings.Index(str[ls:], "\r\n")]
		ls = strings.Index(str, "\r\nContent-Length: ")
		if ls > -1 {
			ls = ls + 18
			var ls_end = strings.Index(str[ls:], "\r\n")
			dataLen, errl := strconv.Atoi(str[ls:ls_end])
			if errl != nil {
				fmt.Println(err)
				return
			}
			if dataLen-(len(str)-head_len) > 0 {
				send_len = ls - (len(str) - head_len) //后面这些字节直接放弃搜索
			}
		}
	*/
	//fmt.Println(11111, str)
	sendData := [][]byte{}
	if buf[0] == 67 && buf[1] == 79 {
		if port == "0" {
			port = "443"
		}
		(*Conn).Write([]byte(ver + " 200 OK\r\nConnection: close\r\nProxy-Connection: close\r\nProxy-agent: LingMax-proxy\r\nProxy-Content-Length: 0\r\nContent-Length: 0\r\n\r\n"))

	} else {
		if port == "0" {
			port = "80"
		}
		lswz := strings.Index(str, " ") + 1
		buf1 := buf[0:lswz]
		buf2 := buf[lswz+7+len(hostPort):]
		allbuf := []byte("")
		for {
			allbuf = append(buf1, buf2...)
			str = string(allbuf)
			wz_head = strings.Index(str, "\r\nProxy-")
			if wz_head < 0 {
				break
			}
			buf1 = allbuf[0:wz_head]
			wz_end = strings.Index(string(allbuf[wz_head+2:]), "\r\n")
			if wz_end < 0 {
				break
			}
			buf2 = allbuf[wz_head+wz_end:]
		}
		//fmt.Println(hostPort)
		//fmt.Println(string(buf2))
		sendData = append(sendData, allbuf)
	}
	//fmt.Println(222222, str)

	hostPort = host + ":" + port
	host = host + "."
	mutexb.Lock()
	_, ok := HostCache[host]
	mutexb.Unlock()
	if !ok {
		sendDnsBuf(host)
		mutexb.Lock()
		_, ok := HostCache[host]
		mutexb.Unlock()
		if !ok {
			(*Conn).Close()
			return

		}
	}
	/*
		for {
			(*Conn).SetReadDeadline((time.Now().Add(100 * time.Millisecond)))
			bufx := make([]byte, 4096)
			len1x, errxa := (*Conn).Read(bufx)
			if errxa != nil || len1x < 1 {
				break
			} else {
				sendData = append(sendData, bufx[:len1x])
			}
		}
	*/

	addx := ""

	d1 := []*IpInfo{}
	mutexb.Lock() //mutex.Unlock()
	for vip := range HostCache[host].ips {
		d1 = append(d1, HostCache[host].ips[vip])
	}
	mutexb.Unlock()
	sort.Slice(d1, func(i, j int) bool {
		return d1[i].ms < d1[j].ms
		//return rand.Intn(1) == 1
	})

	jc := 0
	if ok && len(HostCache[host].ms_ip) > 0 {
		hostPort = HostCache[host].ms_ip + ":" + port
		go httpSend(Conn, hostPort, sendData, &addx, HostCache[host].ms_ip)

	} else {
		go httpSend(Conn, hostPort, sendData, &addx, host)
	}
	jc++
	time.Sleep(2 * time.Second)
	for i1 := 0; i1 < 5; i1++ {
		for i := 0; i < len(d1); i++ {
			if len(addx) > 0 {
				if addx != host && string(addx[len(addx)-1:]) != "." {
					HostCache[host].ms_ip = addx
				}
				return
			}
			if jc >= 5 {
				continue
			}
			hostPort = d1[i].ip + ":" + port
			go httpSend(Conn, hostPort, sendData, &addx, d1[i].ip)
			time.Sleep(2 * time.Second)
			jc++
		}
	}
	defer (*Conn).Close()
	defer func() {
		(*Conn).Write([]byte("HTTP/1.0 500 Connection err \r\nContent-Length: 0\r\nProxy-agent: LingMax-proxy\r\n\r\n"))
	}()

}

func sendDnsBuf(host string) {
	msg := dnsmessage.Message{}
	msg.Header.RecursionDesired = true
	name, _ := dnsmessage.NewName(host)
	rt := dnsmessage.Question{
		Name:  name,
		Type:  dnsmessage.TypeA,
		Class: dnsmessage.ClassINET,
	}
	msg.Questions = []dnsmessage.Question{rt}
	buf, err := msg.Pack()
	if err != nil {
		return
	}
	dnsmsg(buf, xx8877)
}

func httpSend(Conn *net.Conn, hostPort string, sendData [][]byte, addx *string, ip string) {
	if len(*addx) > 0 {
		return
	}
	remote_tcp, err := net.DialTimeout("tcp", hostPort, 10*time.Second) // 3s timeout

	if err != nil {

		//remote_tcp, err = net.DialTimeout("tcp", host+":"+port, 2*time.Second) // 3s timeout
		fmt.Println(err)
		return
	}

	defer remote_tcp.Close()

	if len(sendData) > 0 {
		//fmt.Println(string(sendData))
		for i := 0; i < len(sendData); i++ {
			remote_tcp.Write(sendData[i])
		}

		//go io.Copy(Conn, remote_tcp)
		//io.Copy(remote_tcp, Conn)
		/*
			recv_len := 0
			recv_add := 0

			recv_ssss := -1
			for {
				bufx := make([]byte, 2048)
				len1x, errx := Conn.Read(bufx)
				if errx != nil {
					return
				}
				bufx = bufx[:len1x]
				remote_tcp.Write(bufx)
				if recv_ssss == -1 {
					recv_ssss = 0
					str_recv := string(bufx)

					sssLen := strings.Index(str_recv, "\r\nContent-Length: ")
					if sssLen < 0 {
						return
					}
					sssLen = sssLen + 18
					eeeLen := strings.Index(string(str_recv[sssLen:]), "\r\n")
					if eeeLen < 0 {
						return
					}
					ecx, rerr := strconv.Atoi(str_recv[sssLen:eeeLen])
					if rerr != nil || ecx < 1 {
						return
					}
					recv_len = ecx
					sssLen = strings.Index(str_recv, "\r\n\r\n")
					if sssLen < 0 {
						return
					}
					sssLen = sssLen + 4
					bufx = bufx[sssLen:]
				}
				recv_add = recv_add + len(bufx)
				if recv_len <= recv_add {
					return
				}
			}

		*/
	} else {

		//go io.Copy(Conn, remote_tcp)
		//io.Copy(remote_tcp, Conn)
	}

	//recv := make([]byte, 1)
	//remote_tcp.Read(recv)
	if len(*addx) > 0 {
		return
	}
	mutexb.Lock() //mutex.Unlock()
	(*addx) = ip
	mutexb.Unlock() //mutex.Unlock()
	defer (*Conn).Close()
	/*
		defer func() {
			(*Conn).Write([]byte("HTTP/1.0 500 Connection err \r\nContent-Length: 0\r\nProxy-agent: LingMax-proxy\r\n\r\n"))
		}()
	*/
	//(*Conn).Write(recv)
	go io.Copy(remote_tcp, (*Conn))
	io.Copy((*Conn), remote_tcp)

	//fmt.Println("开始  " + hostPort)
	//fmt.Println("结束  " + hostPort)
}
